#include "app_buffer.h"
#include "log/log.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>


/**
 * 初始化小缓冲区
 */
static SubBuffer *sub_buffer_init(int total_size)
{
    SubBuffer *sub_buffer = malloc(sizeof(SubBuffer));
    sub_buffer->ptr = malloc(total_size);
    sub_buffer->total_size = total_size;
    sub_buffer->len = 0;

    return sub_buffer;
}

Buffer *app_buffer_init(int total_size)
{
    // 分配大缓冲区内存
    Buffer *buffer = malloc(sizeof(Buffer));

    // 初始化2个小缓冲区，并添加到大缓冲区中
    buffer->sub_buffers[0] = sub_buffer_init(total_size);
    buffer->sub_buffers[1] = sub_buffer_init(total_size);

    // 初始化索引属性
    buffer->read_index = 0;
    buffer->write_index = 1;

    // 初始化读锁和写锁
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->write_lock, NULL);

    return buffer;
}

void app_buffer_free(Buffer *buffer)
{
    // 释放小缓冲区中的内存
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[1]->ptr);
    // 释放小缓冲区
    free(buffer->sub_buffers[0]);
    free(buffer->sub_buffers[1]);
    // 释放大缓冲区
    free(buffer);
}

int app_buffer_write(Buffer *buffer, char *data, int data_len)
{
    // data_len的大小不能超过255 =》 后面用一个字节来存储这个值
    if (data_len > 255)
    {
        log_error("要写入的数据超过了一个字节大小");
        return -1;
    }

    log_debug("准备写入数据：%.*s，数据长度为%d， 加锁", data_len, data, data_len);
    // 加锁
    pthread_mutex_lock(&buffer->write_lock);

    // 获取写缓冲区
    SubBuffer *w_buffer = buffer->sub_buffers[buffer->write_index];

    // 如果写缓冲区剩余空间不足， 则错误退出
    if (data_len > w_buffer->total_size - w_buffer->len -1)
    {
        log_error("写缓冲区剩余空间不足");
        // 解锁
        pthread_mutex_unlock(&buffer->write_lock);
        return -1;
    }

    // 写入数据 （先写入数据长度(一个字节)，再写入数据）
    w_buffer->ptr[w_buffer->len] = data_len;
    memcpy(w_buffer->ptr + w_buffer->len + 1, data, data_len);
    
    // 更新写缓冲区的数据长度
    w_buffer->len += data_len + 1;

    // 解锁
    pthread_mutex_unlock(&buffer->write_lock);

    log_debug("准备写入数据完成：%.*s，解锁", data_len, data);

    return 0;
}

void switch_buffer(Buffer *buffer)
{
    log_debug("准备切换缓冲区， 加写锁");
    // 加写锁 =》 防止切换缓冲区时，有其他线程在写缓冲区   不能同时进行
    pthread_mutex_lock(&buffer->write_lock);

    int temp = buffer->read_index;
    buffer->read_index = buffer->write_index;
    buffer->write_index = temp;

    // 解写锁
    pthread_mutex_unlock(&buffer->write_lock);
    log_debug("切换缓冲区完成， 解写锁");
}

int app_buffer_read(Buffer *buffer, char *data_buf, int buf_size)
{

    // 加读锁
    pthread_mutex_lock(&buffer->read_lock);

    log_debug("准备读取数据， 加读锁");

    // 获取读缓冲区
    SubBuffer *r_buffer = buffer->sub_buffers[buffer->read_index];

    // 在准备读之前： 如果读缓冲区没有数据，切换缓冲区
    if (r_buffer->len == 0)
    {
        // 切换缓冲区
        switch_buffer(buffer);
        // 重新获取读缓冲区
        r_buffer = buffer->sub_buffers[buffer->read_index];
        // 如果读缓冲区还是没有数据，则错误退出
        if (r_buffer->len == 0)
        {
            log_error("读缓冲区没有数据");
            // 解锁
            pthread_mutex_unlock(&buffer->read_lock);
            return -1;
        }
    }

    // 读取数据，并保存data_buf中
    // 先得到数据长度 (内存的第一个字节)
    int data_len = r_buffer->ptr[0];
    log_debug("data_len=%d", data_len);
    // 如果数据长度大于buf_size，则错误退出
    if (data_len > buf_size)
    {
        log_error("要读取的数据长度大于buf_size");
        // 解锁
        pthread_mutex_unlock(&buffer->read_lock);
        return -1;
    }

    // 然后根据数据长度读取数据
    memcpy(data_buf, r_buffer->ptr+1, data_len);
    // 将第一帧后面的所有数据移动到起始0位置
    memmove(r_buffer->ptr, r_buffer->ptr+data_len+1,r_buffer->len-data_len-1);

    // 更新读缓冲区的数据长度
    r_buffer->len -= data_len + 1;

    

    // 读取完成后：如果读缓冲区没有数据，切换缓冲区
    if (r_buffer->len == 0)
    {
        switch_buffer(buffer);
    }

    // 解读锁
    pthread_mutex_unlock(&buffer->read_lock);
    log_debug("读取数据完成：%.*s， 解读锁", data_len, data_buf);

    // 返回读取数据的长度
    return data_len;
}